/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mezcla_externa;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;
import mezcla_externa.MemoriaIntermedia.GestorMemoriaIntermedia;

/**
 *
 * @author user
 */

public class MezclaExterna {
    
    public static int[] GenerarArreglo(int numero)
    {
        int[] arreglo = new int[numero];
       
        int i=0;
        while (i<numero){
        Random rand = new Random();
            int x = rand.nextInt(25);
            if (!Existe(arreglo, x)){
            arreglo[i]=x;i++;}
       }
        return arreglo;
    }
      
    public static LinkedList<Integer> GenerarArr(int numero)
    {     
        LinkedList<Integer> lista = new LinkedList<Integer>();       
        int count=0;
        while (count<numero){
        Random rand = new Random();
            int x = rand.nextInt(25);
            if (!lista.contains(x)){
            lista.add(x);count++;}
       }
        return lista;
    }

    public static boolean Existe(int[] arreglo,int x)
    {
        boolean f=false;
        for (int i=0;i<arreglo.length;i++){
            if (arreglo[i]==x){f=true;break;}
        }
        return f;
    } 
   
    public static Tupla TuplaMenor(LinkedList<Pagina> buffer,int indice)
    {
        Tupla tupla = new Tupla();
        for (int i =0;i<buffer.size();i++){
            for (int k =0;k<buffer.get(i).getNumeroDeTuplas();k++){
                if (buffer.get(i).getTuplas().get(k).getIdTupla().getNumero()==indice)
                {
                    tupla = buffer.get(i).getTuplas().get(k);
                    break;
                }
            }
        }
        return tupla;
    }
   
    public static Tupla TuplaMenor(Pagina[] buffer,int indice)
    {
        Tupla tupla = new Tupla();
        for (int i =0;i<buffer.length-1;i++)
        {
            for (int k =0;k<buffer[i].getNumeroDeTuplas();k++)
            {
                if (buffer[i].getNumeroDeTuplas()>0)
                {
                    if (buffer[i].getTuplas().get(k).getIdTupla().getNumero()==indice)
                    {
                        tupla = buffer[i].getTuplas().get(k);
                        buffer[i].getTuplas().remove(k);
                        i=buffer.length;
                        break;

                    }
                }
            }
        }
        return tupla;
    }
   
    public static LinkedList<Pagina> GenerarSecuencia(LinkedList<Pagina> buffer,LinkedList<Integer> indices,Relacion relacion,String nombreArchivo,int n)
    {
        LinkedList<Pagina> secuencia = new LinkedList<Pagina>();
        int a=0;
        while(a<indices.size())
        {
            IdentificadorPagina idPagina = new IdentificadorPagina(nombreArchivo,0);
            Pagina pagina = new Pagina(relacion, idPagina);
            for (int k =0;k<n;k++)
            {
                Tupla tupla = TuplaMenor(buffer, indices.get(a));
                pagina.adicionarTupla(tupla);
                a++;
            }
            secuencia.add(pagina);
        }
        return secuencia;
    }    
   
    public static int PaginaLibre(Pagina[] buffer)
    {
        int resultado=-1;
        for (int i=0;i<buffer.length-1;i++)
        {
            if ((buffer[i]==null)||(buffer[i].getNumeroDeTuplas()==0)){
                resultado=i;
                break;
            }
        }
        return resultado;
    }
   
    public static void main(String[] args) throws FileNotFoundException, IOException 
    {           
        int numerotuplas = 24;
        int numeropaginas = 8;
        int tuplaspagina=3;
        int tamaniobuffer = 4;
        GestorMemoriaIntermedia gmi = new GestorMemoriaIntermedia(tamaniobuffer);
        GestorAlmacenamiento ga = new GestorAlmacenamiento(null, gmi);
        List<Atributo> atributos = new ArrayList<Atributo>();
        atributos.add(new Atributo("integer", Integer.class));
        atributos.add(new Atributo("string", String.class));
        Relacion relacion = new Relacion(atributos);
        String nombreArchivo = "g:/prueba/mezcla.db";
        ga.crearArchivo(nombreArchivo);

        LinkedList<Integer> lista = GenerarArr(numerotuplas);
        GestorIORelacion gestor = new GestorIORelacion(ga, relacion, nombreArchivo);
       
        //crear lista de paginas
        LinkedList<Pagina> listapaginas = new LinkedList<Pagina>();
        int j=0;
        for (int i=0;i<numeropaginas;i++){
            IdentificadorPagina idPagina = new IdentificadorPagina(nombreArchivo, i);
            //para poder recuperar la pagina
            Pagina pagina = new Pagina(relacion, idPagina);
            for (int k=0;k<tuplaspagina;k++){
                List<Comparable> v = new ArrayList<Comparable>();
                v.add(new Integer(23));
                v.add(new String("informacion ....."));
                //crear identificador de pagina
                IdentificadorTupla idT1 = new IdentificadorTupla(nombreArchivo, lista.get(j));
                pagina.adicionarTupla(new Tupla(idT1, v));
                j++;
            }
            listapaginas.add(pagina);
        }
       
        // guardar paginas en disco
        for (int i =0;i<listapaginas.size();i++)
        {
            RandomAccessFile archivoDB = new RandomAccessFile(nombreArchivo,"rw");
            GestorIOPagina.escribirPagina(archivoDB, listapaginas.get(i));
            archivoDB.close();                   
        }
       
        //leer paginas de disco
        LinkedList<Pagina> lista2 = new LinkedList<Pagina>();
        for (int i =0;i<listapaginas.size();i++)
        {
            IdentificadorPagina idPagina = new IdentificadorPagina(nombreArchivo, i);
            lista2.add(ga.leerPagina(relacion,idPagina));
            System.out.println(ga.leerPagina(relacion,idPagina));
        }
       
        nombreArchivo = "g:/prueba/mezcla1.db";
        //llenar buffer con paginas
        LinkedList<Pagina> buffer = new LinkedList<Pagina>();
        LinkedList<LinkedList<Pagina>> archivosecuencia = new LinkedList<LinkedList<Pagina>>();
       
        int a=0;
        while(a<lista2.size())
        {
            LinkedList<Integer> indicestupla = new LinkedList<Integer>();
            for (int i=0;i<tamaniobuffer;i++)
            {
                for (int k=0;k<tuplaspagina;k++)
                {
                    indicestupla.add(lista2.get(a).getTuplas().get(k).getIdTupla().getNumero());
                }
                buffer.add(lista2.get(a));
                a++;
            }
            Collections.sort(indicestupla);
            LinkedList<Pagina> secuencia = GenerarSecuencia(buffer, indicestupla, relacion, nombreArchivo, tuplaspagina);
            archivosecuencia.add(secuencia);
        }
     
       
       
       
        int b=0;
        int indice=0;
        Pagina[] Buffer = new Pagina[tamaniobuffer];
        IdentificadorPagina id = new IdentificadorPagina(nombreArchivo, 0);
        Buffer[tamaniobuffer-1]=new Pagina(relacion, id);
        boolean flag = true;
        LinkedList<Pagina> disco = new LinkedList<Pagina>();
        while (b<lista2.size())
        {
            while ((PaginaLibre(Buffer)!=-1)&&(flag))
            {
                Buffer[PaginaLibre(Buffer)]=archivosecuencia.get(indice).removeFirst();

                if (indice+1>=archivosecuencia.size())indice=0;
                else indice++;
                if (archivosecuencia.get(indice).size()==0)flag=false;
            }
      
            LinkedList<Integer> ind = new LinkedList<Integer>();
            for (int i=0;i<Buffer.length-1;i++)
            {
                if (Buffer[i].getNumeroDeTuplas()>0)
                ind.add(Buffer[i].getTuplas().get(0).getIdTupla().getNumero());
            }
            Collections.sort(ind);

            Tupla tupla = TuplaMenor(Buffer, ind.get(0));
           
            Buffer[tamaniobuffer-1].adicionarTupla(tupla);
            if (Buffer[tamaniobuffer-1].getNumeroDeTuplas()==3)
            {
                disco.add(Buffer[tamaniobuffer-1]);
                b++;
                id = new IdentificadorPagina(nombreArchivo, b);
                Buffer[tamaniobuffer-1]=new Pagina(relacion, id);
            }
        }
       
        for (int i =0;i<disco.size();i++)
        {

            RandomAccessFile archivoDB = new RandomAccessFile(nombreArchivo,"rw");
            GestorIOPagina.escribirPagina(archivoDB, disco.get(i));
            archivoDB.close();
        }
       
        //leer paginas de disco
       
        LinkedList<Pagina> listadisco = new LinkedList<Pagina>();
        for (int i =0;i<disco.size();i++)
        {
            IdentificadorPagina idPagina = new IdentificadorPagina(nombreArchivo, i);
            listadisco.add(ga.leerPagina(relacion,idPagina));
            System.out.println(ga.leerPagina(relacion,idPagina));
         }
                  
    }    
 
}

